﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SarjetLib;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace gitignoreGenerator
{
  public partial class main : Form
  {
    public main()
    {
      InitializeComponent();
    }

    public static Stream ConvertToStream(byte[] bytes)
    {
      Stream result;
      try
      {
        Stream stream = new MemoryStream(bytes);
        result = stream;
      }
      catch (Exception ex)
      {
        throw ex;
      }
      return result;
    }

    public class Comparer : IComparer<ZipArchiveEntry>
    {
      public int Compare(ZipArchiveEntry x, ZipArchiveEntry y)
      {
        return x.Name.CompareTo(y.Name);
      }
    }

    private void main_Load(object sender, EventArgs e)
    {
      CHlpListView lv = new CHlpListView(lsvgn);
      CHlpListView.AddTitile(lsvgn, new string[] { "Lang" }, new int[] { 300 });

      CHlpListView lv2 = new CHlpListView(lsvSel);
      CHlpListView.AddTitile(lsvSel, new string[] { "Lang" }, new int[] { 300 });

      lsvSel.VirtualMode = true;
      lsvSel.VirtualListSize = 0;
      lsvSel.RetrieveVirtualItem += new RetrieveVirtualItemEventHandler((obj, rvie) =>
      {
        rvie.Item = new ListViewItem(new string[] { sellist.Skip(rvie.ItemIndex).First().Key });
      });

      var gzip = ConvertToStream(Properties.Resources.gitignore_main);
      zip = new ZipArchive(gzip, ZipArchiveMode.Read, leaveOpen: false);
      {
        var alist = (from en in zip.Entries where en.Name.EndsWith(".gitignore") select en).ToList();
        list.Clear();
        alist.Sort(new Comparer());
        foreach (var al in alist)
        {
          string kkey = al.Name;
          string namestr = kkey.Substring(0, kkey.Length - 10);
          if (!list.ContainsKey(namestr))
          {
            list.Add(namestr, al);
          }
        }
        foreach (var kv in list)
        {
          string kkey = kv.Key;
          CHlpListView.AddItemLine(lsvgn, kkey);
        }
      }

      GitignoreGenerator();
      var version = GetEdition();
      var sv = version.ToString();
      this.Text = $".gitignore";
      tslTip.Text = "双击列表选择语言";
      tslAuthor.Text = $".gitignore v{sv}";
    }
    public static Version GetEdition()
    {
      return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
    }

    private void lsvgn_DoubleClick(object sender, EventArgs e)
    {
      if (lsvgn.SelectedItems.Count > 0)
      {
        ListViewItem sel = lsvgn.SelectedItems[0];
        if (!sellist.ContainsKey(sel.Text))
        {
          sellist.Add(sel.Text, list[sel.Text]);
          lsvSel.VirtualListSize = sellist.Count;
          GitignoreGenerator();
        }
      }
    }

    private void lsvSel_DoubleClick(object sender, EventArgs e)
    {
      if (lsvSel.SelectedIndices.Count > 0)
      {
        var sel = lsvSel.SelectedIndices[0];
        if (sellist.Count > sel)
        {
          sellist.Remove(sellist.Skip(sel).First().Key);
          lsvSel.VirtualListSize = sellist.Count;
          GitignoreGenerator();
        }
      }
    }

    private void GitignoreGenerator()
    {
      StringBuilder sb = new StringBuilder();
      //# {"Author:", lwidth} {Author}
      //# {"E-mail:", lwidth} {Email}
      string htip = @"# ==================================================== #";
      string tips = $@"# {"Soft:",lwidth} .gitignore Generator";
      sb.AppendLine(htip);
      sb.AppendLine(tips);
      sb.AppendLine($@"#");
      sb.AppendLine($@"# Language List:");
      foreach (var en in sellist)
      {
        sb.AppendLine($@"#    - {en.Key}");
      }
      sb.AppendLine(htip);
      sb.AppendLine();

      foreach (var en in sellist)
      {
        sb.AppendLine();
        string list = $@"[ {en.Key}.gitignore ]";
        string head = GenFixWidthStr(list);
        using (var stream = en.Value.Open())
        using (var reader = new StreamReader(stream))
        {
          sb.AppendLine(head);
          sb.AppendLine(reader.ReadToEnd());
        }
      }
      string tail = "[ End of file ]";
      tail = GenFixWidthStr(tail);
      sb.AppendLine(tail);

      string ssb = sb.ToString();
      string v = ssb.Replace("\n", "\r\n");
      txbGen.Text = v;
      //Console.Write(v);

      var path_gi = Path.Combine(Application.StartupPath, ".gitignore");
      tslTip.Text = "准备更新列表";
      if (File.Exists(path_gi))
      {
        try
        {
          File.Delete(path_gi);
        }
        catch
        {
          tslTip.Text = "文件写错误, 无法删除";
        }
      }
      using (StreamWriter sw = new StreamWriter(path_gi, false, Encoding.UTF8))
      {
        sw.Write(ssb);
      }
      tslTip.Text = "File: ./.gitignore (Clipboard copied)";

      StringCollection filePaths = new StringCollection();
      filePaths.Add(path_gi);
      Clipboard.SetFileDropList(filePaths);
    }

    public static string GenFixWidthStr(string centralText, int width = 50)
    {
      int len = (width - centralText.Length) / 2;
      if (len < 0)
      {
        len = 0;
      }
      string lr = new string('=', len);
      string mid = $@"{lr} {centralText} {lr}";
      if (mid.Length % 2 == 1)
      {
        mid += " ";
      }
      string head = $@"# {mid} #";
      return head;
    }

    Dictionary<string, ZipArchiveEntry> list = new Dictionary<string, ZipArchiveEntry>();
    Dictionary<string, ZipArchiveEntry> sellist = new Dictionary<string, ZipArchiveEntry>();
    ZipArchive zip;
    const string Author = "sarjet";
    const string Email = "sarjet@qq.com";
    const int lwidth = -16;

    private void lsvgn_KeyDown(object sender, KeyEventArgs e)
    {
      if (e.KeyCode == Keys.Enter)
      {
        lsvgn_DoubleClick(this, null);
      }
    }

    private void lsvSel_KeyDown(object sender, KeyEventArgs e)
    {
      if (e.KeyCode == Keys.Escape)
      {
        sellist.Clear();
        lsvSel.VirtualListSize = sellist.Count;
        GitignoreGenerator();
      }
    }

    private void tslAuthor_Click(object sender, EventArgs e)
    {
      var version = GetEdition();
      var sv = version.ToString();
      tslAuthor.Text = Authors ? $"Author: sarjet" : $".gitignore v{sv}";
      Authors = !Authors;
    }

    public bool Authors = true;
  }
}
